package cn.edu.dlmu.cogo.framework;

import cn.edu.dlmu.cogo.framework.annotation.CogoApplication;
import cn.edu.dlmu.cogo.framework.annotation.ComponentScan;
import cn.edu.dlmu.cogo.framework.context.*;
import cn.edu.dlmu.cogo.framework.utils.ApplicationContextAwareUtil;
import cn.edu.dlmu.cogo.framework.utils.CogoClassUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;


/**
 * @author yixi
 */
public class CogoStarter {

    public static ApplicationContext run(Class<?> clazz) {
        long start = System.currentTimeMillis();
        showBanner();
        CogoApplication cogoApplication = clazz.getAnnotation(CogoApplication.class);
        if (cogoApplication == null) {
            Console.error("{} 主类缺少注解[@CogoApplication]",Environment.getSystemTime());
            return null;
        }
        Console.log("{} [CogoFramework]开始启动",Environment.getSystemTime(),clazz.getName());
        CogoClassUtil.setMainClass(clazz);

        // 自定义排除特定类
        for (Class<?> exclude : cogoApplication.excludes()) {
            ApplicationContextAwareUtil.removeClass(exclude);
        }

        // 初始化扫描包路径
        initialize(clazz);

        // 自动排除特定的实现了ApplicationContextAware接口的类
        CogoClassUtil.getClassesExtendClass(ExcludeClass.class).forEach(exclude -> ApplicationContextAwareUtil.removeClass(
                ReflectUtil.invoke(ReflectUtil.newInstance(exclude),
                        ReflectUtil.getMethodByName(exclude,"exclude"))));

        // 按优先级反射执行所有实现ApplicationContextAware接口的实例中的setApplicationContext方法
        ApplicationContextAwareUtil.initialize(CogoClassUtil.getClassesExtendClass(ApplicationContextAware.class));
        try {
            ApplicationContextAwareUtil.invoke();
        } catch (Exception e) {
            Console.error("{} [CogoFramework]启动失败",Environment.getSystemTime(),clazz.getName());
            e.printStackTrace();
            return null;
        }

        long end = System.currentTimeMillis();
        Console.log("{} [CogoFramework][{}]启动成功，启动用时[{}ms]",Environment.getSystemTime(), clazz.getName(), (end-start));
        Console.log("===============================================================================================");
        return ContextContainer.getApplicationContext();
    }

    /**
     * 初始化扫描包路径
     */
    private static void initialize(Class<?> clazz){
        // 以主类为基准，初始化当前工程下的所有类
        CogoClassUtil.initialize(ClassUtil.scanPackage(ClassUtil.getPackage(clazz)));

        // 初始化CogoFramework的所有类
        CogoClassUtil.initialize(ClassUtil.scanPackage("cn.edu.dlmu.cogo"));

        // 初始化用户自定义目录下的所有类
        for (String packageName : clazz.getAnnotation(CogoApplication.class).componentScan()) {
            CogoClassUtil.initialize(ClassUtil.scanPackage(packageName));
        }

        // 初始化ComponentScan注解标记的类，但是需要确保该类可以被扫描到
        for (Class<?> classWithComponentScan : CogoClassUtil.getClassesWithAnnotation(ComponentScan.class, false)) {
            for (String packageName : classWithComponentScan.getAnnotation(ComponentScan.class).value()) {
                CogoClassUtil.initialize(ClassUtil.scanPackage(packageName));
            }
        }
    }

    private static void showBanner() {
        Console.log("   _____                      _____                   _             \n" +
                "  / ____|                    |  __ \\                 (_)            \n" +
                " | |     ___   __ _  ___     | |__) |   _ _ __  _ __  _ _ __   __ _ \n" +
                " | |    / _ \\ / _` |/ _ \\    |  _  / | | | '_ \\| '_ \\| | '_ \\ / _` |\n" +
                " | |___| (_) | (_| | (_) |   | | \\ \\ |_| | | | | | | | | | | | (_| |\n" +
                "  \\_____\\___/ \\__, |\\___/    |_|  \\_\\__,_|_| |_|_| |_|_|_| |_|\\__, |\n" +
                "               __/ |                                           __/ |\n" +
                "              |___/                                           |___/ ");
    }
}
